3.1 DartVM 自举
runtime/vm/bootstrap.cc
文件是 Dart VM 引导过程的核心部分,主要职责是初始化 Dart VM 的核心状态,加载基础库,并为后续的 Dart 代码执行准备必要的环境。这个文件在 Dart VM 的启动过程中起着关键作用,确保 VM 能够正确加载和初始化所有必要的组件。主要功能:
-
DoBootstrapping 函数:这是引导过程的主入口函数。它接收一个 kernel 二进制文件作为输入,并完成以下任务:
- 创建并注册所有引导库(bootstrap libraries)的 Library 对象。
- 调用 BootstrapFromKernel 函数来从 kernel 文件加载实际的库内容。
-
BootstrapFromKernel 函数:这个函数负责从 kernel 二进制文件中读取和加载库的内容。主要步骤包括:
- 使用 kernel::Program::ReadFromBuffer 解析 kernel 二进制数据。
- 创建 kernel::KernelLoader 对象来加载库。
- 按照预定义的顺序加载所有引导库。
- 调用 Finish 函数完成引导过程。
- 初始化对象存储(object store)中的已知对象。
- 加载平台二进制文件中可能包含的其他库(如
dart:_builtin
或dart:io
)。
-
Finish 函数:这个函数完成引导过程的最后阶段:
- 设置本地解析器(native resolver)。
- 处理待定类(pending classes)的最终化(finalization)。
- 确保
_Closure
类被急切编译(eagerly compiled),因为它是所有闭包实例的类。
-
CollectTokenPositionsFor 函数:这个函数收集给定脚本的所有标记位置(token positions)。它遍历所有库和类,收集函数、字段和类的标记位置信息。
-
CollectConstConstructorCoverageFrom 函数:这个函数收集给定脚本中的常量构造函数覆盖信息。它用于支持常量覆盖分析。
BootstrapLibProps
定义 BootstrapLibProps 结构体,用于存储引导库的属性
struct BootstrapLibProps {
ObjectStore::BootstrapLibraryId index;
const char* uri;
};
枚举
定义一些常量,用于在后续操作中索引数组:
enum {
kPathsUriOffset = 0,
kPathsSourceOffset = 1,
kPathsEntryLength = 2
};
创建引导库的属性
定义一个宏,用于创建引导库的属性
#if !defined(DART_PRECOMPILED_RUNTIME)
#define MAKE_PROPERTIES(CamelName, name) \
{ObjectStore::k##CamelName, "dart:" #name},
static const BootstrapLibProps bootstrap_libraries[] = {
FOR_EACH_BOOTSTRAP_LIBRARY(MAKE_PROPERTIES)};
#undef MAKE_PROPERTIES
注:FOR_EACH_BOOTSTRAP_LIBRARY 的声明:
// A list of the bootstrap libraries including CamelName and name.
//
// These are listed in the order that they are compiled (see vm/bootstrap.cc).
#define FOR_EACH_BOOTSTRAP_LIBRARY(M) \
M(Core, core) \
M(Async, async) \
M(Collection, collection) \
M(Convert, convert) \
M(Developer, developer) \
M(Ffi, ffi) \
M(Internal, _internal) \
M(Isolate, isolate) \
M(Math, math) \
M(Mirrors, mirrors) \
M(TypedData, typed_data) \
M(VMService, _vmservice)
计算引导库的数量
// 计算引导库的数量
static constexpr intptr_t kBootstrapLibraryCount =
ARRAY_SIZE(bootstrap_libraries);
BootstrapFromKernel
static ErrorPtr BootstrapFromKernel(Thread* thread,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size) {
Zone* zone = thread->zone();
const char* error = nullptr;
// 从 kernel buffer 读取程序
std::unique_ptr<kernel::Program> program = kernel::Program::ReadFromBuffer(
kernel_buffer, kernel_buffer_size, &error);
if (program == nullptr) {
// 如果读取失败,创建并返回错误信息
const intptr_t kMessageBufferSize = 512;
char message_buffer[kMessageBufferSize];
Utils::SNPrint(message_buffer, kMessageBufferSize,
"Can't load Kernel binary: %s.", error);
const String& msg = String::HandleNew(message_buffer, Heap::kOld);
return ApiError::New(msg, Heap::kOld);
}
// 使用长跳转设置错误处理
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
// 创建 KernelLoader 对象
kernel::KernelLoader loader(
program.get(),
/*uri_to_source_table=*/nullptr);
auto isolate_group = thread->isolate_group();
// 如果需要混淆,读取混淆禁止列表
if (isolate_group->obfuscate()) {
loader.ReadObfuscationProhibitions();
}
// 按顺序加载引导库
Library& library = Library::Handle(zone);
for (intptr_t i = 0; i < kBootstrapLibraryCount; ++i) {
ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
library = isolate_group->object_store()->bootstrap_library(id);
loader.LoadLibrary(library);
}
// 完成引导过程,包括类的最终化
Finish(thread);
isolate_group->object_store()->InitKnownObjects();
// 加载平台二进制文件中可能包含的其他库
const Object& result = Object::Handle(zone, loader.LoadProgram());
program.reset();
if (result.IsError()) {
return Error::Cast(result).ptr();
}
// 如果是预编译模式,读取加载单元
if (FLAG_precompiled_mode) {
loader.ReadLoadingUnits();
}
return Error::null();
}
// 如果发生错误,返回粘性错误
return Thread::Current()->StealStickyError();
}
本文作者:Maeiee
本文链接:3.1 DartVM 自举
版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!
喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!